#region Copyright

#endregion
#region Usings

using System;
using System.Collections;
using System.Collections.Generic;
using System.Web;
using System.Web.Caching;
using TamoCRM.Core.Common.Null;
using TamoCRM.Core.ComponentModel;
using TamorCRM.Core.Caching;


#endregion

namespace TamoCRM.Core.Caching
{
	
    public abstract class CachingProvider
    {
		#region Private Members

        private static System.Web.Caching.Cache _cache;
        private const string CachePrefix = "TamoCRM_";
		
		#endregion

		#region Protected Properties

		/// <summary>
		/// Gets the default cache provider.
		/// </summary>
		/// <value>HttpRuntime.Cache</value>
        protected static System.Web.Caching.Cache Cache
        {
            get
            {
                return _cache ?? (_cache = HttpRuntime.Cache);
            }
        }
		
		#endregion

		#region Shared/Static Methods

		/// <summary>
		/// Cleans the cache key by remove cache key prefix.
		/// </summary>
		/// <param name="CacheKey">The cache key.</param>
		/// <returns>cache key without prefix.</returns>
		/// <exception cref="ArgumentException">cache key is empty.</exception>
        public static string CleanCacheKey(string CacheKey)
        {
            if (String.IsNullOrEmpty(CacheKey))
            {
                throw new ArgumentException("Argument cannot be null or an empty string", "CacheKey");
            }
            return CacheKey.Substring(CachePrefix.Length);
        }

		/// <summary>
		/// Gets the cache key with key prefix.
		/// </summary>
		/// <param name="CacheKey">The cache key.</param>
		/// <returns>CachePrefix + CacheKey</returns>
		/// <exception cref="ArgumentException">Cache key is empty.</exception>
        public static string GetCacheKey(string CacheKey)
        {
            if (string.IsNullOrEmpty(CacheKey))
            {
                throw new ArgumentException("Argument cannot be null or an empty string", "CacheKey");
            }
            return CachePrefix + CacheKey;
        }

		/// <summary>
		/// Instances of  caching provider.
		/// </summary>
		/// <returns>The Implemments provider of cache system defind in web.config.</returns>
        public static CachingProvider Instance()
        {
            return ComponentFactory.GetComponent<CachingProvider>();
        }
		
	#endregion

	    #region Private Methods
	
        private void ClearCacheInternal(string prefix, bool clearRuntime)
        {
            foreach (DictionaryEntry objDictionaryEntry in HttpRuntime.Cache)
            {
                if (Convert.ToString(objDictionaryEntry.Key).StartsWith(prefix))
                {
                    if (clearRuntime)
                    {
						//remove item from runtime cache
                        RemoveInternal(Convert.ToString(objDictionaryEntry.Key));
                    }
                    else
                    {
						//Call provider's remove method
                        Remove(Convert.ToString(objDictionaryEntry.Key));
                    }
                }
            }
        }

        private void RemoveCacheKey(string CacheKey, bool clearRuntime)
        {
            if (clearRuntime)
            {
				//remove item from runtime cache
                RemoveInternal(GetCacheKey(CacheKey));
            }
            else
            {
				//Call provider's remove method
                Remove(GetCacheKey(CacheKey));
            }
        }

        private void RemoveFormattedCacheKey(string CacheKeyBase, bool clearRuntime, params object[] parameters)
        {
            if (clearRuntime)
            {
				//remove item from runtime cache
                RemoveInternal(string.Format(GetCacheKey(CacheKeyBase), parameters));
            }
            else
            {
				//Call provider's remove method
                Remove(string.Format(GetCacheKey(CacheKeyBase), parameters));
            }
        }
		
		#endregion

		#region Protected Methods

		/// <summary>
		/// Clears the cache internal.
		/// </summary>
		/// <param name="cacheType">Type of the cache.</param>
		/// <param name="data">The data.</param>
		/// <param name="clearRuntime">if set to <c>true</c> clear runtime cache.</param>
        protected void ClearCacheInternal(string cacheType, string data, bool clearRuntime)
        {
            switch (cacheType)
            {
                case "Prefix":
                    ClearCacheInternal(data, clearRuntime);
                    break;                            
            }
        }

	    /// <summary>
		/// Removes the internal.
		/// </summary>
		/// <param name="cacheKey">The cache key.</param>
        protected void RemoveInternal(string cacheKey)
        {
			//attempt remove from private dictionary
            DataCache.RemoveFromPrivateDictionary(cacheKey);
            //remove item from memory
            if (Cache[cacheKey] != null)
            {
                Cache.Remove(cacheKey);
            }
        }

		/// <summary>
		/// Clears the specified type.
		/// </summary>
		/// <param name="type">The type.</param>
		/// <param name="data">The data.</param>
        public virtual void Clear(string type, string data)
        {
            ClearCacheInternal(type, data, false);
        }

        public virtual IDictionaryEnumerator GetEnumerator()
        {
            return Cache.GetEnumerator();
        }

		/// <summary>
		/// Gets the item.
		/// </summary>
		/// <param name="cacheKey">The cache key.</param>
		/// <returns>cache content</returns>
        public virtual object GetItem(string cacheKey)
        {
            return Cache[cacheKey];
        }

		/// <summary>
		/// Inserts the specified cache key.
		/// </summary>
		/// <param name="cacheKey">The cache key.</param>
		/// <param name="itemToCache">The object.</param>
        public virtual void Insert(string cacheKey, object itemToCache)
        {
            Insert(cacheKey, itemToCache, null as TamoCRMCacheDependency, System.Web.Caching.Cache.NoAbsoluteExpiration, System.Web.Caching.Cache.NoSlidingExpiration, CacheItemPriority.Default, null);
        }

		/// <summary>
		/// Inserts the specified cache key.
		/// </summary>
		/// <param name="cacheKey">The cache key.</param>
		/// <param name="itemToCache">The object.</param>
		/// <param name="dependency">The dependency.</param>
        public virtual void Insert(string cacheKey, object itemToCache, TamoCRMCacheDependency dependency)
        {
            Insert(cacheKey, itemToCache, dependency, System.Web.Caching.Cache.NoAbsoluteExpiration, System.Web.Caching.Cache.NoSlidingExpiration, CacheItemPriority.Default, null);
        }

		/// <summary>
		/// Inserts the specified cache key.
		/// </summary>
		/// <param name="cacheKey">The cache key.</param>
		/// <param name="itemToCache">The object.</param>
		/// <param name="dependency">The dependency.</param>
		/// <param name="absoluteExpiration">The absolute expiration.</param>
		/// <param name="slidingExpiration">The sliding expiration.</param>
        public virtual void Insert(string cacheKey, object itemToCache, TamoCRMCacheDependency dependency, DateTime absoluteExpiration, TimeSpan slidingExpiration)
        {
            Insert(cacheKey, itemToCache, dependency, absoluteExpiration, slidingExpiration, CacheItemPriority.Default, null);
        }

		/// <summary>
		/// Inserts the specified cache key.
		/// </summary>
		/// <param name="cacheKey">The cache key.</param>
		/// <param name="itemToCache">The value.</param>
		/// <param name="dependency">The dependency.</param>
		/// <param name="absoluteExpiration">The absolute expiration.</param>
		/// <param name="slidingExpiration">The sliding expiration.</param>
		/// <param name="priority">The priority.</param>
		/// <param name="onRemoveCallback">The on remove callback.</param>
        public virtual void Insert(string cacheKey, object itemToCache, TamoCRMCacheDependency dependency, DateTime absoluteExpiration, TimeSpan slidingExpiration, CacheItemPriority priority,
                                   CacheItemRemovedCallback onRemoveCallback)
		{
		    Cache.Insert(cacheKey, itemToCache, dependency == null ? null : dependency.SystemCacheDependency, absoluteExpiration, slidingExpiration, priority, onRemoveCallback);
		}


		/// <summary>
		/// Removes the specified cache key.
		/// </summary>
		/// <param name="CacheKey">The cache key.</param>
        public virtual void Remove(string CacheKey)
        {
            RemoveInternal(CacheKey);
        }
		
		#endregion

        
    }
}